////////////////////////////////////////////////////////////////////////
// This file is part of the simpleSID framework
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
//
// Copyright (c)Richard White, 2009
// See License.txt for a disclaimer of all warranties
// and licensing information

#include "RWSID.h"
#pragma once



//This clas is used to replicate some of the features of the 6510 CPU There are no interupts and there are no BCD and this needs to be heavily rewritten
class CPU6510
{
private:
		//Private member varibales first
	unsigned char m_byMemory[0xffff]; //Memory of 6510
	unsigned char A, X, Y, SP, SR; // your basic regs of the 6510 Acumulator X, Y, Stack Pointer, Status Register
	unsigned short PC; //Program counter
	unsigned char *m_pCurrentMemory; //Pointer to the firat instruction that is the opcode
	unsigned long m_ulClock; //How many clock cycles it has taken
	float m_fClockFreq;
	RWSID *m_pSID;

	

	//These const variables are for the flag of the status register
	static const unsigned char kFlag_N = 0x80;
	static const unsigned char kFlag_V = 0x40;
	static const unsigned char kFlag_B = 0x10;
	static const unsigned char kFlag_D = 0x08;
	static const unsigned char kFlag_I = 0x04;
	static const unsigned char kFlag_Z = 0x02;
	static const unsigned char kFlag_C = 0x01;
	

		//Private functions accessed from with the class and not directly
	void Push(unsigned char byValue);
	unsigned char Pop();
	void SetFlag(unsigned char kFlag, int nVal); //if value is true set flag
	void Branch();

	//Opcode Declarations
	void ADC();
	void AND();
	void ASL();
	void BCC();
	void BCS();
	void BEQ();
	void BIT();
	void BMI();
	void BNE();
	void BRK();
	void BPL();
	void BVC();
	void BVS();
	void CLC();
	void CLD();
	void CLI();
	void CLV();
	void CMP();
	void CPX();
	void CPY();
	void DEC();
	void DEX();
	void DEY();
	void EOR();
	void INC();
	void INX();
	void INY();
	void JMP();
	void JSR();
	void LDA();
	void LDX();
	void LDY();
	void LSR();
	void NOP();
	void ORA();
	void PHA();
	void PHP();
	void PLA();
	void PLP();
	void ROL();
	void ROR();
	void RTI();
	void RTS();
	void SBC();
	void SEC();
	void SED();
	void SEI();
	void STA();
	void STX();
	void STY();
	void TAX();
	void TAY();
	void TSX();
	void TXA();
	void TXS();
	void TYA();
	void NotImplemented();

	//Addressing Mode Declarations TODO: change the modes so that they read from the SID class but should work for the time being
	unsigned char LoadAbsolute();
	unsigned char LoadAbsoluteX();
	unsigned char LoadAbsoluteY();
	unsigned char LoadAccumulator();
	unsigned char LoadImmediate();
	unsigned char LoadIndirect();
	unsigned char LoadIndirectX();
	unsigned char LoadIndirectY();
	unsigned char LoadRelative(); // for branch statements i think i need the contents of branch() in here?
	unsigned char LoadZeroPage();
	unsigned char LoadZeroPageX();
	unsigned char LoadZeroPageY();

	void StoreAbsolute(unsigned char byValue);
	void StoreAbsoluteX(unsigned char byValue);
	void StoreAbsoluteY(unsigned char byValue);
	void StoreAccumulator(unsigned char byValue);
	void StoreImmediate(unsigned char byValue);
	void StoreIndirect(unsigned char byValue);
	void StoreIndirectX(unsigned char byValue);
	void StoreIndirectY(unsigned char byValue);
	void StoreRelative(unsigned char byValue);
	void StoreZeroPage(unsigned char byValue);
	void StoreZeroPageX(unsigned char byValue);
	void StoreZeroPageY(unsigned char byValue);
	

public:
	CPU6510(RWSID *pSID);
	virtual ~CPU6510();

	struct Opcodes
	{
		void (CPU6510::*Instruction)();
		unsigned char (CPU6510::*LoadAddress)();
		void (CPU6510::*StoreAddress)(unsigned char);
		unsigned char NumBytes;
		unsigned char Cycles;
	};
	static const Opcodes m_Opcodes[256]; 
	
	void Init();
	void Reset();
	void ResetTo(unsigned short wPC, unsigned char byA, unsigned char byX = 0, unsigned char byY = 0);
	unsigned long Execute(unsigned int nInstructions); //Will execute however many instructions.

	void SetMemory(unsigned short byAddress, unsigned char byValue);
	unsigned char GetMemory(unsigned short byAddress);
	
	void SetClockFreq(float fClockFreq);
	float GetClockFreq();
	unsigned long GetCycles(); //This will return the full amount of cycles the processer has done 
};